﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Drawing;
using System.IO;

namespace DotaHelp.Models
{
    public class RecipeDrawItem
    {
        public Item Item { get; set; }
        public RecipeDrawItem[] Childs;
        public Point Position { get; set; }
        public bool IsRecipe { get; set; }
       

        private int Column { get; set; }

        public IEnumerable<RecipeDrawItem> Foreach()
        {
            yield return this;
            foreach (var c in Childs)
            {

                foreach (var c2 in c.Foreach())
                {
                    yield return c2;
                }
            }
        }
                

        public int Height
        {
            get
            {
                return Childs.Any() ? Childs.Sum(a => a.Height) : 1;
            }
        }

        public const int size = 64;
        private const int xpref = 100;
        private const int ypref = 15;
        private const int prefFromSize = 20;

        public Bitmap Draw(DotaModel m, Color lineColor)
        {
            var bitmap = new Bitmap
            (
                (Foreach().Max(a => a.Column) + 1) * (size + xpref) - xpref + prefFromSize * 2,
                Height * (size + ypref) + prefFromSize * 2
            );

            using (var g = Graphics.FromImage(bitmap))
            {
                foreach (var x in Foreach())
                {
                    foreach (var c in x.Childs)
                    {
                        var ps = new[] { 
                            new Point(x.Position.X + size, x.Position.Y + size / 2), 
                            new Point(x.Position.X + size + xpref / 2, x.Position.Y+ size / 2),
                            new Point(x.Position.X + size + xpref / 2, c.Position.Y+ size / 2),
                            new Point(c.Position.X , c.Position.Y+ size / 2)
                        };

                        using (var pen =new Pen(lineColor, 2))
                        {
                            g.DrawBeziers(pen, ps);
                        }
                    }

                    if (!x.IsRecipe)
                    {
                        g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAliasGridFit;
                        g.TextContrast = 0;
                        using (var brush = new SolidBrush(Color.FromArgb(255, 194, 0)))
                        using (var font = new Font("Tahoma", 10, FontStyle.Bold, GraphicsUnit.Point))
                        using (var format = new StringFormat() { Alignment = StringAlignment.Center })
                        {
                            g.DrawString(
                                x.Item.Price.ToString(),
                                font,
                                brush,
                                new Rectangle(x.Position.X, x.Position.Y + size, size, size),
                                format
                                );
                        }
                    }
                }
            }
            return bitmap;
        }

        public static RecipeDrawItem Load(DotaModel model, int itemId)
        {  
            var result = model.LoadRecursiveRecipes(itemId).ToArray();
            
            Func<int, Item> build = id=>{
                var row = result.First(r=>r.ForItemId == id);
                return new Item()
                {
                    Id = id,
                    ImageId = (int)row.ImageId,
                    Price = (int)row.Price,
                    Name = row.Name,
                    Nickname = row.Nickname
                };
            };

            Func<int, int[]> children = id => result
                .Where(r => r.ForItemId == id)
                .Where(r => r.ItemId != null) // если есть хоть один связанный предмет
                .SelectMany(r => Enumerable.Range(0, r.Count ?? 1).Select(n => r)) // может быть несколько одинаковых предметов в рецепте
                .Select(r => (int)r.ItemId)
                .ToArray();


            Func<int, int?, int, RecipeDrawItem> R = null;
            R = (id, parentId, column) => new RecipeDrawItem()
            {
                Item = build(id),
                Childs = id != parentId
                    ? children(id).Select(childId => R(childId, id, column + 1)).OrderBy(c => c.Item.Price).ToArray()
                    : new RecipeDrawItem[0],
                IsRecipe = id == parentId,
                Column = column
            };

            var root = R(itemId, null, 0);
            Rec(root, 0);
            return root;
        }

        private static void Rec(RecipeDrawItem parent, int ny)
        {
            parent.Position = new Point(prefFromSize + parent.Column * (size + xpref), prefFromSize + ny + (parent.Height * (size + ypref)) / 2 - size / 2);

            foreach (var c in parent.Childs)
            {
                Rec(c, ny);
                ny += c.Height * (size + ypref);
            }
        }
    }
}